package com.heima.gateway.ruotes;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigAutoConfiguration;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * 动态路由更新
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class DynamicRouteLoader {
    private final NacosConfigManager nacosConfigManager;

    private final RouteDefinitionWriter writer;

    private String dataId = "gateway-routes.json";

    private String group = "DEFAULT_GROUP";

    private final Set<String> routeIds = new HashSet();

    private final RouteDefinitionLocator routeDefinitionLocator;
    // 清除所有路由
    public Mono<Void> deleteAllRoutes() {
        return routeDefinitionLocator.getRouteDefinitions()
                .map(RouteDefinition::getId)
                .collectList()
                .flatMap(ids -> Flux.fromIterable(ids)
                        .flatMap(routeId -> writer.delete(Mono.just(routeId)))
                        .then()
                );
    }

    public List<RouteDefinition> getCurrentRoutes() {
        return routeDefinitionLocator.getRouteDefinitions()
                .collectList()
                .block(); // 注意：block() 是同步阻塞操作，适合用于调试或接口调用
    }


    @PostConstruct
    public void initRouteConfigListener() throws NacosException {
//        deleteAllRoutes().subscribe();
//        1.拉取一次配置并添加配置监听（添加了监听的路由表）
        String routeConfig = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

//                    2.1监听配置
                    @Override
                    public void receiveConfigInfo(String configInfo) {
//                        2.2监听到配置改变，更新路由表
                        updateRouteConfig(configInfo);

                    }
                }

        );
//        3.第一次读取到配置，更新路由表
        updateRouteConfig(routeConfig);
    }

    /**
     * 更新路由表
     */
    public void updateRouteConfig(String routeConfig){
        log.info("监听到路由配置信息:{}",routeConfig);

//        JSON格式的配置信息更新解析，YAML格式不好解析
//        1.解析配置信息，转为RouteDefinition对象
        List<RouteDefinition> routes = JSONUtil.toList(routeConfig, RouteDefinition.class);
        for (String routeId : routeIds) {
//            2.删除路由表,在对路由更新时，不是覆盖掉旧的路由而是新增路由，所以需要先删除旧的路由
            writer.delete(Mono.just(routeId)).subscribe();
        }
        routeIds.clear();
        System.out.println("All：" + getCurrentRoutes());
        for (RouteDefinition route : routes) {
//            3.添加路由表
            writer.save(Mono.just(route)).subscribe();
//            4.保存路由ID
            routeIds.add(route.getId());
        }
        System.out.println("All：" + getCurrentRoutes());


    }


}
